<!-- Created by henian.xu on 2018/11/27. -->

<!--<template>
    <div class="menu">
        <div
            class="item"
            v-for="(item,index) in 3"
            :key="index">
            <div class="label">item1</div>
            <div class="sub-menu">
                <div
                    class="item"
                    v-for="(item,index) in 3"
                    :key="index">
                    <div class="label">item2 item2 </div>
                    <div class="sub-menu">
                        <div
                            class="item"
                            v-for="(item,index) in 3"
                            :key="index">
                            <div class="label">item3 item3 </div>
                            <div class="sub-menu">
                                <div
                                    class="item"
                                    v-for="(item,index) in 3"
                                    :key="index">
                                    <div class="label">item4 item4 </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>-->

<script>
export default {
    name: 'Menu',
    data() {
        return {
            currentItem: {},
            openedMap: [],
        };
    },
    props: {
        data: {
            type: Array,
            default() {
                return [];
            },
        },
        prop: {
            type: Object,
            default() {
                return {
                    id: 'id',
                    label: 'label',
                    icon: 'icon',
                    children: 'children',
                };
            },
        },
        openedList: {
            type: Array,
            default() {
                return [];
            },
        },
        uniqueOpened: {
            type: Boolean,
            default: false,
        },
        isNav: {
            type: Boolean,
            default: false,
        },
    },
    computed: {
        options() {
            const { prop, openedList } = this;
            const recursion = (arr, lv = 0) =>
                arr.map(item => {
                    const obj = {
                        id: item[prop.id],
                        label: item[prop.label],
                        icon: item[prop.icon],
                        __parent: arr,
                    };
                    if (item[prop.children]) {
                        obj.children = recursion(item[prop.children], lv + 1);
                        // 内部属性
                        const opened = openedList[lv] || {};
                        if (typeof opened === 'string' || typeof opened === 'number') {
                            obj.__open = opened + '' === item[prop.id] + '';
                        } else if (Array.isArray(opened)) {
                            obj.__open = opened.includes(item[prop.id]);
                        } else {
                            obj.__open = !!opened[item[prop.id]];
                        }
                    }
                    return obj;
                });
            return recursion(this.data);
        },
        dataMap() {
            // const flatten = (arr, obj = {}) =>
            //     arr.reduce((p, c) => ((p[c.id] = c), c.children ? flatten(c.children, p) : p), obj);
            return this.$utils.Comm.listToMap(this.data);
        },
        optionsMap() {
            return this.$utils.Comm.listToMap(this.options);
        },
    },
    watch: {
        openedList: {
            handler(val) {
                this.openedMap = [];
                val.forEach(opened => {
                    if (typeof opened === 'string' || typeof opened === 'number') {
                        this.openedMap.push({ [opened]: true });
                    } else if (this.uniqueOpened) {
                        console.error('[components:menu]当 uniqueOpened = true 时 openedList 不可为多维数组');
                    } else if (Array.isArray(opened)) {
                        this.openedMap.push(opened.reduce((p, c) => ((p[c] = true), p), {}));
                    } else {
                        this.openedMap.push(opened);
                    }
                });
            },
            immediate: true,
        },
    },
    methods: {
        onItem($event, item, lv) {
            if (item.__open === undefined) {
                this.currentItem = item;
            } else {
                this.switchItem(item, lv);
                this.$forceUpdate();
            }
        },
        switchItem(item, lv) {
            if (item.__open === undefined) return;
            item.__open = !item.__open;

            const { openedMap, uniqueOpened, optionsMap } = this;
            if (uniqueOpened) {
                // 截取当前级数及以下的所有展开项并闭关
                openedMap
                    .splice(lv, openedMap.length)
                    .forEach(item => Object.keys(item).forEach(key => (optionsMap[key].__open = false)));
            }
            // 记录已展开的项
            const lvMap = (openedMap[lv] = openedMap[lv] || {});
            if (item.__open) {
                lvMap[item.id] = item.__open;
            } else {
                delete lvMap[item.id];
            }
        },
    },
    render() {
        const { options, currentItem, onItem, isNav } = this;
        const buildSubMenu = (item, lv) => {
            if (!item || !Array.isArray(item.children)) return;
            return <div class="sub-menu">{buildMenu(item.children, lv + 1)}</div>;
        };
        const buildArrows = (item, lv) => {
            if (item.__open === undefined) return;
            if (isNav && lv) {
                return item.__open ? (
                    <icon class="icon-arrow" unicode="&#xf104;" />
                ) : (
                    <icon class="icon-arrow" unicode="&#xf105;" />
                );
            }
            return item.__open ? (
                <icon class="icon-arrow" unicode="&#xf106;" />
            ) : (
                <icon class="icon-arrow" unicode="&#xf107;" />
            );
        };
        const buildMenu = (arr, lv = 0) => {
            return arr.map(item => {
                return (
                    <div class={['item', { open: item.__open }, { active: currentItem.id === item.id }]}>
                        <div
                            class="label"
                            style={lv && !isNav ? { 'padding-left': `calc(${lv}em + 10px)` } : {}}
                            on-click={$event => {
                                $event.stopPropagation();
                                onItem($event, item, lv);
                            }}
                            on-mouseenter={$event => {
                                $event.stopPropagation();
                                onItem($event, item, lv);
                                // console.log(1111, $event);
                            }}
                            on-mouseleave={$event => {
                                $event.stopPropagation();
                                onItem($event, item, lv);
                                console.log(1111, $event);
                            }}
                        >
                            <icon unicode={item.icon} />
                            <span>
                                {item.label}-{item.id}
                            </span>
                            {buildArrows(item, lv)}
                        </div>
                        {buildSubMenu(item, lv)}
                    </div>
                );
            });
        };
        return <div class={['menu', { nav: isNav }]}>{buildMenu(options)}</div>;
    },
};
</script>

<style lang="scss">
.menu,
.sub-menu {
    > .item {
        position: relative;
        cursor: pointer;
        > .label {
            position: relative;
            padding: 0 $padding;
            @include text-line(1);

            > .icon-arrow {
                position: absolute;
                right: $padding;
                top: 50%;
                margin-top: -0.5em;
                line-height: 1;
            }

            &:hover {
                background-color: $color-main;
                color: #fff;
            }
        }
        &.open {
            > .sub-menu {
                display: block;
            }
        }
        &.active {
            > .label {
                background-color: $color-second;
                color: #fff;
            }
        }
    }
}

.sub-menu {
    display: none;
    // box-shadow: 0 4px 10px -5px #000;

    > .item {
    }
}

.menu.nav {
    @include clearfix;

    > .item {
        float: left;
    }

    .sub-menu {
        position: absolute;
        left: 0;
        top: 100%;
        .sub-menu {
            left: 100%;
            top: 0;
        }
    }

    &,
    .sub-menu {
        > .item {
            > .label {
                > .icon-arrow {
                    position: static;
                }
            }
            &:hover {
                > .sub-menu {
                    /*display: block;*/
                }
            }
        }
    }
}
</style>
